/***************************************************************************
 *   oboe.core.Controller						  *
 *   Copyright (C) 2011 by Felipe Manga					*
 *   lufeboma@gmail.com							*
 *									 *
 *   Permission is hereby granted, free of charge, to any person obtaining *
 *   a copy of this software and associated documentation files (the	   *
 *   "Software"), to deal in the Software without restriction, including   *
 *   without limitation the rights to use, copy, modify, merge, publish,   *
 *   distribute, sublicense, and/or sell copies of the Software, and to	*
 *   permit persons to whom the Software is furnished to do so, subject to *
 *   the following conditions:						 *
 *									 *
 *   The above copyright notice and this permission notice shall be	*
 *   included in all copies or substantial portions of the Software.	   *
 *									 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,	   *
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF	*
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR	 *
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
 *   OTHER DEALINGS IN THE SOFTWARE.					   *
 ***************************************************************************/

package oboe.core;

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;

import oboe.utils.CallbackHandle;
import oboe.utils.Prototype;

import flash.Vector;

class Controller extends SigSlot
{

private var displayObject:DisplayObject;
private var callbacks:Vector<CallbackHandle>;

public function new( displayObject:DisplayObject=null )
{
	if( !displayObject )
	{
	displayObject = new Sprite();
	}
	this.displayObject = displayObject;
	Oboe.controllerLookup[ displayObject ] = this;
}

private function addAssetCallback( name:String, func:Function, arguments:Array<Dynamic> ):CallbackHandle
{
	var cb:CallbackHandle;
	if( !this.callbacks ) this.callbacks = new Vector();
	arguments.unshift( func );
	arguments.unshift( name );
	arguments.unshift( this.displayObject );
	cb = Prototype.addCallback.apply( null, arguments );
	this.callbacks.push( cb );
	return cb;
}

private function removeAssetCallback( key:CallbackHandle ):Void
{
	var i:Int = callbacks.indexOf( key );
	if( i==-1 ) return;
	// Object(this.displayObject).removeCallback( key );
	Prototype.removeCallback( this.displayObject, key );
	this.callbacks[i] = this.callbacks[ this.callbacks.length-1 ];
	this.callbacks.pop();
}

private function releaseDisplayObject():Void
{
	this.displayObject = null;
}

private function setDisplayObject( ndo:DisplayObject, preserveCallbacks:Bool=false ):Void
{
	var parent:DisplayObjectContainer;
	if( this.displayObject )
	{
	Oboe.controllerLookup.delete( this.displayObject );
	if( this.displayObject.parent )
	{
		parent = this.displayObject.parent;
		var z:Int = parent.getChildIndex(this.displayObject);
		parent.addChildAt( ndo, z );
		parent.removeChild( this.displayObject );
	}
	}
	this.displayObject = ndo;
	Oboe.controllerLookup[ ndo ] = this;
	
	if( preserveCallbacks )
	{
	for( c in this.callbacks )
	{
		this.displayObject.addEventListener( c.event, c.cb );
	}
	}
	else
	{
	this.callbacks = null;
	}
}

private override function removeChild(child:SigSlotCollection):Void
{
	super.removeChild( child );
	if( Std.is( child, Controller ) )
	{
	var c:Controller = Controller(child);
	if( c.displayObject && c.displayObject.parent == this.displayObject )
	{
		DisplayObjectContainer(this.displayObject).removeChild( c.displayObject );
	}
	}
}

private override function addChild(child:SigSlotCollection):Void
{
	if( Std.is( child, Controller ) )
	{
	DisplayObjectContainer(this.displayObject).addChild( Controller(child).displayObject ); 
	}
	super.addChild( child );
}

private function getDisplayObject():DisplayObject
{
	return this.displayObject;
}

}